# Python 是强类型的动态脚本语言。
# 变量定义：变量是用于存储数据值的标识符（名字）
# 强类型：不允许不同类型相加。
# 动态：不使用显示数据类型声明，且确定一个变量的类型是在第一次给它赋值的时候。
# 脚本语言：一般也是解释型语言，运行代码只需要一个解释器，不需要编译。



# linux 伙伴系统 扩容方式 2 的整数幂，list 2倍扩容能高效匹配，减少内存碎片
# Windows 1.5倍扩容，能更好的复用旧的内存块
import sys
ls = []
print(sys.getsizeof(ls))
for i in range(30):
    print("---------- begin:  ", sys.getsizeof(ls), len(ls))
    
    ls.append(i)
    print("end:  ", sys.getsizeof(ls), len(ls))
    


# 解释 a=256; b=256; a is b 返回 True，而 x=257; y=257; x is y 返回 False 的原因。
# 小整数池范围（[-5, 256]）的底层实现原理及性能权衡



# typedef struct { ----------- list
#     PyObject_VAR_HEAD
#     PyObject **ob_item;  // 指向元素数组的指针   ----------- 二级指针
#     Py_ssize_t allocated; // 已分配的内存空间大小
# } PyListObject;


# typedef struct {
#     PyObject_VAR_HEAD
#     PyObject *ob_item[1];  // 柔性数组，实际大小由ob_size决定
# } PyTupleObject;

# ---------------------- 元组（tuple） -------------------------
# 存储多个有序且不可变（immutable）的元素 ； 只有一个元素时 (a,) 必须有逗号
# 不可变的，这意味着一旦创建，就不能修改其内容

# 不可变的好处：
# 安全性**：确保元组中的数据不会被意外修改。
# 可哈希性**：因为元组是不可变的，所以它可以作为字典的键或集合的元素（只要元组内的所有元素都是可哈希的）。而列表则不行。
# 线程安全**：在多线程环境中，不可变对象可以被共享而不需要加锁。


# 元组的使用场景
# 保护数据：不被更改
# 字典的键
# 解包返回多个值


# 性能分析
# 创建速度**：元组的创建速度比列表快。因为元组是不可变的，解释器可以对其进行优化
# 访问速度**：元组和列表在元素访问上性能相当，都是O(1)时间复杂度
# 内存占用**：元组比列表占用更少的内存，因为元组不可变，不需要存储额外的空间来应对可能的动态变化


# 命名元组保留了元组的不可变性和性能，同时增加了可读性
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y)   # 10 20





# 垃圾回收机制：
# 主要基于引用计数，辅以标记-清除和分代回收两种机制来提高效率和解决特定问题
# 引用计数是 Python 对象管理的核心，每个对象都有一个引用计数器，计数器为零时，立即回收。 此时 __del__ 会被自动调用。

# 为了解决循环引用问题，Python 引入了标记-清除机制。这个机制会在没有空闲内存时，从根对象出发，遍历所有对象，标记所有可达对象。
#     清除所有未被标记的对象。这种方法可以有效地处理容器对象（如列表、字典、集合）之间的循环引用。
# 分代回收是基于这样一个假设：存活时间越长的对象越不可能是垃圾
# Python 将对象分为三代，新创建的对象在第一代，随着时间推移，存活的对象会被移动到第二代和第三代
# 每一代都有一个阈值，当代内的对象数量达到阈值时，就会触发垃圾回收。这种方法可以减少全面垃圾回收的次数，提高效率。


# ---------------------- 结构化数组 -------------------------
# 结构化数组的本质是​​单块连续内存​​，每个字段（如 x、y、z）的偏移量和数据类型（dtype）在创建时固定



# ---------------------- classmethod -------------------------
# 类方法可以访问类属性，也可以修改类状态，但是不能访问实例属性；实现 "多态构造函数"，支持在继承链中动态创建子类对象，符合开闭原则

        # 有多个构造入口的类
        # 需要访问或修改类属性
        # 继承友好的工厂方法
        # 实现多态行为


# 替代构造函数（工厂模式）
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    @classmethod
    def from_birth_year(cls, name, birth_year):
        age = datetime.now().year - birth_year  # 动态计算年龄
        return cls(name, age)  # 等价于 Person(name, age)

# 使用工厂方法创建实例
p = Person.from_birth_year("Alice", 1990)

# 操作类属性


# 继承时的多态行为：当子类继承时，类方法中的`cls`会自动绑定到子类，因此可以在子类中重写类方法，实现多态
class Base:
    @classmethod
    def create(cls):
        print(f"Created from {cls.__name__}")
        return cls()

class Child(Base): pass

Child.create()  # 输出: "Created from Child" (cls 自动指向 Child)





# ---------------------- staticmethod -------------------------
# 与类逻辑相关但无需状态的工具函数
# 模块化优势：避免污染全局命名空间，将功能关联性强的函数组织到类中，提升代码可读性
# 性能比类方法略块




# ---------------------- classmethod-staticmethod ------高级用法-------------------
# 组合使用 @classmethod 和 @staticmethod： --- 子类可重写 _create_connection 实现多态
class Database:
    _connection = None
    
    @classmethod
    def get_connection(cls):
        if cls._connection is None:
            cls._connection = cls._create_connection()
        return cls._connection
    
    @staticmethod
    def _create_connection():
        print("Creating new DB connection...")
        return "Connection Object"


# 确保一个类只有一个实例（这里是数据库连接），并提供全局访问点（`get_connection` 方法）
# 使用类变量 `_connection` 存储唯一实例，通过类方法 `get_connection` 控制实例的创建（首次调用时创建，之后直接返回）
# `_connection` 是类变量（所有实例共享），而非实例变量。这确保了无论创建多少个 `Database` 实例（如果有），`_connection` 都是同一个
#  `get_connection` 是类方法：第一个参数 `cls` 指向当前类（`Database` 或子类）。这使得在子类调用时，`cls` 自动指向子类，从而支持多态





# --------------------------------- @property -------------------------------
# 仅定义@property而不设setter，防止外部修改
# 在setter方法中添加类型和范围检查，防止非法赋值
# 延迟加载；首次访问时执行耗时计算，结果缓存供后续使用。
# 避免复杂计算
# 属性合法校验，联动更新，只读，动态计算



# --------------------------------- __del__ -------------------------------
# 优先使用上下文管理器（with语句）   【__enter__  __exit__】
# 避免循环引用，用weakref替代强引用
# 保持__del__方法简单且无异常
# 子类需调用父类的__del__





# __str__(self)：返回对象的可读字符串表示形式，通常用于 print。
# __repr__(self)：返回对象的官方字符串表示，应该尽可能能够用来重新创建该对象。
# __str__和__repr__的区别，并举例说明
# __repr__通常用于开发和调试,返回的字符串应该是有效的 Python 表达式，可以用 eval() 函数来重建原对象。
# __str__为用户提供一个可读性好的字符串表示，适合展示给用户看,返回一个简单的或更加容易理解的字符串表示


"""


__getitem__(self, key)：定义对象的索引访问，使用 obj[key] 语法时调用。
__setitem__(self, key, value)：定义对象的索引赋值，使用 obj[key] = value 语法时调用。

                        __getitem__和__setitem__的应用场景是什么  封装底层数据​​：隐藏内部数据结构，提供统一接口



__delitem__(self, key)：定义对象的索引删除，使用 del obj[key] 语法时调用。



__contains__(self, item)：定义成员检查，使用 item in obj 语法时调用。


__call__(self, ...)：允许类实例像函数一样被调用。    --------------   如何使用__call__使得一个对象可以像函数一样被调用
__call__ 逻辑应保持单一职责，超过 20 行代码需考虑拆分为辅助方法




__hash__(self)：定义对象的哈希值，通常用于集合和字典中的键。  ---------------何时需要使用__hash__方法，为什么hashable对象重要

__enter__(self) 和 __exit__(self, exc_type, exc_value, traceback)：用于上下文管理器，支持 with 语句


"""




"""
链式装饰器
提示：如果要使用多个装饰器修饰同一个函数，如何实现？请提供示例。
如何在类中使用装饰器？请说明实例方法和静态方法的区别。
应用场景
functools.wraps的作用
"""




"""
asyncio模块是Python内置的库，用于编写单线程的异步代码。它提供了事件循环、协程和任务的功能，
使得程序能够在等待I/O操作（例如网络请求、文件操作等）时，不会阻塞整个程序的执行


asyncio的核心是事件循环，它负责调度和执行异步任务。事件循环不断检查是否有准备好的任务，执行这些任务并处理I/O事件。

协程是用async def定义的函数，允许在执行时被中断，等待某个操作完成后再恢复执行,
await关键词可以暂停协程的执行，等待另一个协程或I/O操作完成。
通过事件循环，asyncio允许运行多个协程而不是并行执行多个线程，减少上下文切换的开销。

import asyncio
import aiohttp

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    urls = ['https://example.com' for _ in range(5)]
    tasks = [fetch(url) for url in urls]
    results = await asyncio.gather(*tasks)
    for content in results:
        print(content)

if __name__ == '__main__':
    asyncio.run(main())

    

请阐述asyncio的事件循环是什么，以及它的工作原理。
    事件循环是asyncio库的核心调度器，负责协调异步任务的执行。
        它通过单线程实现高并发，尤其适合处理I/O密集型操作（如网络请求、文件读写）。其核心作用包括：
    ​​任务调度​​：管理协程（Coroutine）的启动、暂停、恢复和完成。
    ​​资源复用​​：避免线程/进程切换的开销，通过非阻塞I/O最大化CPU利用率。
    ​​事件响应​​：监听I/O操作的状态变化（如网络数据到达、文件读写完成），触发回调

    1. 协程封装为Task对象（Task是Future的子类，代表异步操作的执行状态），加入任务队列
    2.  事件循环从队列中取出​​就绪的任务​​（非阻塞状态）。
        执行任务代码，直到遇到await表达式（如I/O操作、延时等），此时协程​​主动挂起​​并交出控制权。
        ​关键点​​：挂起时不会阻塞线程，事件循环立即切换到其他任务
    
    3. ​​I/O多路复用（事件通知机制）​​
        使用操作系统级I/O多路复用技术监听阻塞操作：
            Linux：epoll
            macOS/FreeBSD：kqueue
            Windows：IOCP（I/O完成端口）。
        当I/O操作完成（如网络数据到达），操作系统通知事件循环，对应任务被标记为​​就绪​​，重新加入队列

​    4. 当挂起的任务等待的条件满足（如I/O完成或超时），事件循环将其​​从挂起点恢复执行​​


asyncio ​​不绕过GIL​​，但通过I/O操作释放GIL的特性实现并发：
    当协程因I/O挂起时，线程释放GIL，允许其他协程执行。
    ​​优势​​：避免多线程的锁竞争和上下文切换开销。
    ​​局限性​​：对CPU密集型任务，单线程事件循环仍受限于GIL，需结合多进程

asyncio.gather()：并发执行多个任务并收集结果。
asyncio.wait()：动态监控任务完成状态





与传统的多线程编程相比，asyncio有哪些优势和劣势
        高并发 I/O 密集型任务：单线程内通过事件循环（Event Loop）管理成千上万个协程（Coroutine），
                            避免线程切换开销（上下文切换、锁竞争等），适合网络请求、文件 I/O 等场景。
        资源占用低：一个协程仅需几 KB 内存，而一个线程通常需要 MB 级内存，可轻松支持数万并发连接。
        无锁编程：协程在单线程内顺序执行，无需互斥锁（Lock），避免死锁问题（但需注意异步操作的原子性）。
        清晰的异步代码流：async/await 语法使异步代码类似同步结构，可读性优于回调地狱（Callback Hell）。

        
    如何原子操作：
        1. 将涉及共享资源的操作封装为​​不可中断的同步代码块​​，确保在让出前完成所有步骤（不使用 await）
        2. 协程安全容器​​：使用asyncio.Queue等专为协程设计的数据结构
        3. 

        
如何在asyncio中处理异常？

什么是asyncio的并发模式，如何实现




"""
# --------------------------协程--多进程---混合--------------------------
import asyncio
import concurrent.futures

async def hybrid_app():
    # I/O 密集型任务 (使用 asyncio)
    data = await fetch_network_data()
    
    # CPU 密集型任务 (移交进程池)
    loop = asyncio.get_running_loop()
    with concurrent.futures.ProcessPoolExecutor() as pool:
        result = await loop.run_in_executor(pool, process_data, data)
    
    # 后续异步操作
    await save_result(result)

# 启动应用
asyncio.run(hybrid_app())




""""
                创建百万级实例如何节省内存

可以定义类的 slot 属性，用它来声明实例属性的列表，可以用来减少内存空间的目的
class User1:
    def __init__(self, id, name, sex, status):
        self.id = id
        self.name = name
        self.sex = sex
        self.status = status

class User2:
    __slots__ = ['id', 'name', 'sex', 'status']
    def __init__(self, id, name, sex, status):
        self.id = id
        self.name = name
        self.sex = sex
        self.status = status
        
u1 = User1('01', 'rocky', '男', 1)
u2 = User2('02', 'leey', '男', 1)


set(dir(u1)) - set(dir(u2)) ={'__weakref__', '__dict__'}



"""



"""
python  内存管理， 调优手段

"""


"""
不可变参数用值传递

像整数和字符串这样的不可变对象，是通过拷贝进行传递的，因为你无论如何都不可能在原处改变不可变对象

可变参数是引用传递的

比如像列表，字典这样的对象是通过引用传递、和 C 语言里面的用指针传递数组很相似，可变对象能在函数内部改变。

"""


"""
为什么函数名字可以当做参数用？
Python 中一切皆对象，函数名是函数在内存中的空间，也是一个对象
"""



"""
map, reduce,filter
"""


# 减少指令数​​：复杂操作（如嵌套循环）会生成更多字节码，使用内置函数（如map()、filter()）可减少指令量。
# ​​避免动态属性修改​​：运行时修改对象属性（如setattr()）会触发字节码重建，影响性能。
# ​​查看字节码​​：通过dis模块分析代码生成的字节码，定位低效操作（如冗余加载）
# 对象复用​​：高频创建小对象（如循环内）会触发内存分配，可用__slots__减少内存开销

# GIL限制多线程并行，针对不同场景优化：
# ​​I/O密集型​​：用asyncio或threading（线程在I/O等待时释放GIL）。
# ​​CPU密集型​​：用multiprocessing绕过GIL，或使用C扩展（如Cython）。
# ​​替代解释器​​：PyPy（JIT编译）或Jython（无GIL）

# 优先选字典/集合做成员检查；用元组替代不可变列表减少内存
# 局部变量 > 全局变量​​：局部变量访问快（PVM通过LOAD_FAST指令直接读取），全局变量需LOAD_GLOBAL查表

# 不推荐：频繁访问全局变量
global_var = 10
def slow_func():
    for _ in range(1000):
        print(global_var)
# 推荐：转为局部变量
def fast_func():
    local_var = global_var
    for _ in range(1000):
        print(local_var)

# ​​列表推导式​​：比append循环快（字节码更简洁）。
# ​​生成器​​：大数据流处理用yield，避免内存溢出        

# 异步与并行​​
# ​​I/O密集型​​：asyncio避免阻塞（如网络请求）。
# ​​CPU密集型​​：multiprocessing.Pool并行处理（如p.map(func, data)）



# 单利：
import threading  # 实现线程安全
class Singleton(type):
    _instance = {}
    _lock = threading.Lock()
    def __call__(cls, *args, **kwds):
        with cls._lock:
            if cls not in cls._instance:
                cls._instance[cls] = super().__call__(*args, **kwds)
            
        return cls._instance[cls]
#  使用
class DatabaseConnection(metaclass=Singleton):
    pass

# 比较简单的方式
class DatabaseConnection:
    _instance = None
    _lock = threading.Lock()
    def __new__(cls):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super().__new__(cls)
                # 初始化数据库连接
        return cls._instance


# ---------------------------------------------------工厂模式--------------------------------------
# 模拟Django ORM的工厂模式
class Model:
    class objects:
        @classmethod
        def create(cls, **kwargs):
            # 在实际的Django中，这里会根据模型类创建并保存一个实例
            # 我们这里模拟这一行为
            instance = cls(**kwargs)
            instance.save()
            return instance

    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)
    
    def save(self):
        print(f"保存模型实例: {self.__dict__}")

# 定义一个模型
class User(Model):
    pass

# 使用工厂方法创建对象
user = User.objects.create(name="Alice", email="alice@example.com")




# 一切皆对象
# 深入dict和set
# 元类编程
# 魔法方法详解
# 迭代器和生成器详解
# 多线程、多进程和线程池编程
# 深入对象和类socket编程
# 详解协程和异步IO
# Python序列协议
# 对象引用和可变性、垃圾回收
# asyncio并发编程

# —— 面向对象 ——
# 鸭子类型
# 抽象基类
# 类变量、对象变量的查找顺序
# 静态方法、类方法、实例方法
# 数据封装和私有属性
# 对象的自省机制
# 上下文管理器
# contextlib实现上下文管理器
# super函数的查找顺序
# mixin继承模式的应用

# —— asyncio并发编程 ——
# 事件循环
# 协程嵌套
# call_soon、call_later、call_at
# call_soon_threadsafe
# ThreadPoolExecutor+asyncio
# asyncio 模拟 http 请求
# future 和 task
# asyncio 同步和通信
# aiohttp 实现高并发爬虫

# —— 多线程 ——
# GIL和多线程
# 线程通信-共享变量、Queue
# 线程同步-Lock、RLock、Condition、Semaphor
# 线程池和源码分析-ThreadPoolExecutor
# 多进程-multiprocessing
# 进程间通信

# —— 异步IO ——
# IO多路复用-select、poll、epoll
# select+回调+事件循环模
# 生成器进阶-send、close、throw和yield from
# async和await

# —— 元类 ——
# property动态属性
# __getattr__、__getattribute__区别
# 属性描述符
# __new__和__init__
# 元类实现ORM



# --------------------------------------------------------------------
# 设计模式
# 应用架构


# --------------------------- 前向引用​​ -----------------------------------------
# 互相引用
class Employee:
    manager: "Manager"  # 前向引用Manager类   <-------- 类似 c++ 的前置声明

class Manager:
    team: list[Employee]

# 复杂类型注解​​：在函数返回值或参数中引用后续定义的类
def create_node() -> "Node":  # Node类在后续定义
    pass    

class Node: ...

# ​​模块间循环导入（Circular Imports）​​：模块A依赖模块B，同时模块B依赖模块A时，需通过字符串注解避免导入错误


# 解决方案：
# 字符串字面量化：将类型名作为字符串传递，延迟求值至实际使用时
class Tree:
    def __init__(self, left: "Tree", right: "Tree"):  # 用字符串包裹类型
        self.left = left
        self.right = right

# from __future__ import annotations：强制所有注解存储为字符串，在运行时按需解析
from __future__ import annotations  # 必须放在模块顶部；仅Python 3.7+支持
class Tree:
    def __init__(self, left: Tree, right: Tree):  # 无需引号，自动字符串化
        self.left = left
        self.right = right        

# 类型别名：通过别名将前向引用定义为字符串，后续直接使用别名
from typing import TypeAlias
TreeRef: TypeAlias = "Tree"  # Python 3.10+

class Tree:
    def __init__(self, left: TreeRef, right: TreeRef): ...









# CPU密集型任务与GIL规避策略    
from concurrent.futures import ProcessPoolExecutor

@app.get("/cpu-intensive")
def heavy_computing():
    with ProcessPoolExecutor() as pool:
        result = pool.submit(calculate_primes, 10**6)  # 绕过GIL
    return {"result": result}










#  -------------------同步 阻塞----------------------------------
# 阻塞： 线程等待资源被系统挂起，暂停运行，被动等待资源
# 同步： 执行顺序是从上往下运行调用方，必须等待操作完成才能执行后续逻辑，主动等待结果
# 非阻塞： 线程等待期间不被挂起，调用后立即返回，需要轮询或时间监听得到状态，可能因为频繁轮询消耗更多的cpu资源
# 异步： 任务执行顺序，不用等待结果，通过回调，事件通知处理结果，依赖时间通知机制，cpu利用率高